Data Structures

Arrays

| Arrays are homogeneous structures.
| An array is something that you can stick a lot of different things into, but all of them must be the same type.
| An array is a group of things that are together because they are the same type not necessarily the same value.

Arrays
An example

| Let us consider an array of social security numbers. Let picture of the disk represents each of the numbers:
| <data type> <array name>[<size>];
| int SSN[5];
| SSN[1] = 345;

Arrays
Declaration

| An array is a collection of variables of the same type. Individual array elements are identified by an integer index. In C the index begins at zero and is always written inside square brackets.
| int results[20];
| int results_2d[20][5];
| int results_3d[20][5][3];

Arrays
Initialisation

Declarations of arrays (Cont.)
Pascal C/C++

| var
| a: array[0..9] of integer;
| b: array[0..4, 0..9] of integer;
| int a[10];
| float b[5][10];
| Arrays in C always have subscripts ranging from 0 to declared size – 1.

Arrays
An Example

| #include <iostream.h>
| int main() {
| int x, y, anarray[8][8];//declares an array like a chessboard
| for(x=0; x<8; x++) { // sets the element to
| for(y=0; y<8; y++) { // zero; after the loop all
| anarray[x][y]=0; // elements == 0
| } }
| for(x=0; x<8;x++) {
| for(y=0; y<8; y++) { cout<<"anarray["<<x<<"]["<<y<<"]="<<anarray[x][y]<<" ";
| } }
| return 0;
| }

Arrays and functions
An Example

| int add_array(int array[], int size)
| {
| int i;
| int total = 0;
| for (i=0; i < size; i++)
| total += array[i];
| return(total);
| }

Arrays:
Things to remember

| An array identifier is a constant pointer.
| Arrays are stored by rows.
| Let AnArray be a 2-dimensional array of type type.
| The type of AnArray is a pointer to a row.
| The type of *AnArray is a pointer to type.
| In the expression AnArray+i, i is scaled by the size of the row.
| In the expression *AnArray+i, i is scaled by the size of type.
| *AnArray = AnArray[0]
| **AnArray = *(AnArray[0]) = AnArray[0][0]
| AnArray[i] = *(AnArray+i) = *AnArray + i* number of columns

Arrays:
Things to remember

| If AnArray is a single-dimensional array of type type passed as parameter to a function, AnArray may be declared as
| type AnArray[];
| The size of AnArray may be specified, but it is neglected.
| type * AnArray;
| If AnArray is 2-dimensional array of type passed as parameter to a function, AnArray may be declared as
| type AnArray[][size2];
| And the specification of the constant size2 must not be omitted.

Pointers

| Pointers are data types.
| They store memory addresses of variables.

Pointers:
Definition

| The pointer is like any other variable except that the value stored in it has a different interpretation: It is the address of some memory location.
| Pointer is variable that holds a memory address

Pointer:
Interpretation

| ThePointer is defined as a variable of the type pointer to integer, or simply, pointer. Assume value 5FA62 is stored in ThePointer. This value is interpreted as a memory address.
| If the contents of memory location 5FA62 is 658, then the value of ThePointer is 5FA62 and ThePointer points to the value 658.
| Sometimes the address stored in a pointer is not important, so the following abbreviation can be used:

Pointer:
Dereferencing mechanism

| Since the value stored in a pointer is a memory address, the language has to provide a dereferencing mechanism: the mechanism that can be used to access the value pointed to by the pointer. &px has the value 654.
| & is called the address operator.

Dereferencing pointers and the address operator

| Dereferencing refers to accessing the value that a pointer points to.
| To do this “*” operator that interprets single argument as an address and returns the contents of the address as the value of the operation. Usage:
| *p
| EXAMPLE:
| int i = 25, *j;
| Here, j is a pointer to integer. Assume i and j are allocated memory cells at addresses 5FA62 and 5FA70, respectively. This means that the value of i is 25, &i is 5FA62 and the value of &j is 5FA70.

Pointer:
Accessing data

| The initial value of a variable, including a pointer variable, is undetermined. Let assume that the initial value stored in p is 5FA62:

Pointer:
Accessing data

| The initial value of a variable, including a pointer variable, is undetermined. Let assume that the initial value stored in p is 5FA62:

Pointer Assignment Ex.5300

Pointerst Test yourself

| #include <iostream.h>
| int main()
| {
| int x; //A normal integer
| int *pointer; //A pointer to an integer
| pointer=&x; //Read it,
| //"pointer equals the address of x“
| cin>>x; //Reads in x
| cout<<*pointer; //Note the use of the * to // output the actual number stored in x
| return 0;
| }

Pointers
Pascal C/C++

| var
| p: ^integer;
| first: ^student;
| struct student *first;

Pointers (Cont.)
Pascal C/C++

| type
| stuptr = ^node;
| var
| first: stuptr;
| typedef
| struct student *stuptr;
| stuptr first;

The NULL pointer

| The special value NULL can be assigned to the pointer to indicate that its value is defined but that it does not point to anything.
| The NULL is usually equal to 0.
| A convenient way to set the initial value of a pointer to NULL is in the definition itself:
| int *pi = NULL, *pj = NULL;

Dynamic memory allocation

| In C++, the new and delete operators provide build-in language support for dynamic memory allocation and deallocation.
| This feature has several benefits:
| Reduces common programmer errors: it is easy to forget to multiply the number of objects being allocated by sizeof when using malloc.
| Enhances source code clarity: generally, there is no need to: (1) declare operator new and delete, (2) explicitly use casts, or (3) explicitly check the return value.
| Improves run-time efficiency: (1) users can redefine operator new and delete globally and also define then on a per-class basis and (2) calls can be inlined.

new() operator

| The keyword new is used to initialise pointers with memory from free store (a section of memory available to all programs).
| int *ptr = new int;
| It initialises ptr to point to a memory address of size int (because variables have different sizes, number of bytes, this is necessary). The memory that is pointed to becomes unavailable to other programs. This means that the careful coder will free this memory at the end of its usage.

delete() operator

| The delete operator frees up the memory allocated through new. To do so, the syntax is as in the example. delete ptr; After deleting a pointer, it can be a good idea to reset it to point to NULL.
| NULL is a standard compiler-defined statement that sets the pointer to point to, literally, nothing. By doing this, you minimise the potential for doing something foolish with the pointer.

new() and delete()
Example

| int main() {
| }

new() and delete()
Some remarks

| new returns a pointer to the allocated memory
| The storage duration of the new object is from the point of creation until the operator delete destroys it by deallocating its memory, or until the end of the program.
| By default, an allocation failure (such as insufficient or fragmented heap memory) results in the predefined exception bad_alloc being thrown.
| You should use the delete operator to remove all memory which has been allocated by the new operator. Failure to free memory can result in memory leaks.
| The delete operator offers dynamic storage deallocation, deallocating a memory block allocated by a previous call to new.

Example: allocate 2D array, initialise and delete it.

| #include <iostream.h>
| void display(long double **);
| void de_allocate(long double **);
| int NumRows = 3;
| int NumCols = 5;
| void display(long double **data) {
| for (int i = 0; i < m; i++) {
| for (int j = 0; j < n; j++)
| cout << data[i][j] << " ";
| cout << "\n" << endl;
| }
| }

Example: allocate 2D array, initialise and delete it.

| void de_allocate(long double **data) {
| for (int i = 0; i < NumRows; i++)
| delete[] data[i]; // STEP 1: delete the columns
| delete[] data; // STEP 2: delete the rows
| }
| void initialise(long double ** data){
| for (int i = 0; i < NumRows; i++)
| for (int j = 0; j < NumCols; j++)
| data[i][j] = i + j; // arbitrary initialisation
| }

Example: allocate 2D array, initialise and delete it.

| int main(void) {
| long double **data;
| data = new long double*[NumRows]; // STEP 1: SET UP THE ROWS.
| for (int j = 0; j < NumRows; j++)
| data[j] = new long double[NumCols];
| // STEP 2: SET UP THE COLUMNS
| initialise(data);
| display(data);
| de_allocate(data);
| return 0;
| }

Arrays and Pointers

| One thing that arrays don't require that other variables do, is a reference operator when you want to have a pointer to the string.
| EXAMPLE:
| //As opposed to

Arrays and Pointers

| The array can be initialised using pointers as follows.
| ArrayExample = new int[25];
| which allows to access ArrayExample just as if it were an array. Keep in mind that to use delete you must put [] between delete and ArrayExample to tell it to free all 25 bytes of memory allocated. delete [] ArrayExample;

The heap

| The new routine reserves a block of memory of the requested size in a pool of free memory called the heap.
| Two separate data storage areas are used by the program during run time: the stack and the heap.
| The lifetime of data stored on the stack is relative to the lifetime of the subroutine that the data are defined in.
| The lifetime of data stored in the heap starts with the execution of the allocation procedure new and ends when the deallocation procedure delete is called.

heap operations
Advanced

| Works with vectors
| A heap is a binary tree in which every node is larger than the values associated with either child. A heap and a binary tree, for that matter, can be very efficiently stored in a vector, by placing the children of node i in positions 2 * i + 1 and 2 * i + 2.
| Using this encoding, the largest value in the heap is always located in the initial position, and can therefore be very efficiently retrieved.

heap operations
Advanced

| Works with vectors
| A heap is a binary tree in which every node is larger than the values associated with either child. A heap and a binary tree, for that matter, can be very efficiently stored in a vector, by placing the children of node i in positions 2 * i + 1 and 2 * i + 2.
| Using this encoding, the largest value in the heap is always located in the initial position, and can therefore be very efficiently retrieved.

heap operations
Advanced

| A heap is a particular organization of elements in a range between two random access iterators [a, b). Its two key properties are:
| 1. *a is the largest element in the range.
| 2. *a may be removed by the pop_heap algorithm, or a new element can be added by the push_heap
| algorithm, in O(logN) time.
| These properties make heaps useful as priority queues.
| The heap algorithms use less than (operator<) as the default comparison. In all of the algorithms, an alternate comparison operator can be specified.

Pointers:
Things to remember

| Pointers are NOT integers.
| Always to test whether or not memory allocation requests are successful.
| Only memory that has been allocated using new (or the related routines) should be freed using delete operator.
| To pass a parameter by variable, specify this parameter that is a pointer, use a pointer to pointer.
| Always cast the NULL pointer when it is passed as an actual parameter.
| Do not declare pointer as a global variable.

Glossary

| Allocation of memory The action of acquiring a block of memory from the heap.
| Deallocation of memory The action of returning a block of memory to the heap.
| Dereferencing of a pointer’s value The value pointed to by a pointer.
| Heap A pool of free memory. Dynamic memory requires allocate memory from this area.
| Pointer A variable whose value is interpreted as a memory address. A pointer points to the value stored in the location at that address.

Structures
Declaration

| Structure type
| Structure variable

Structures
Declaration: Example (Step 1)

| Structure type
| Structure variable

Structures
Declaration: Example (Step 2)

| Structure type
| Structure variable

Structures
Declaration: Example (Step 3)

| Structure type
| Structure variable

Structures
Declaration: Example (Step 4)

| Structure type
| Structure variable

Structures
Initialisation Test yourself

| A C structure variable may be initialised when it is declared.

Structures and Arrays
Initialisation

| A C structure variable may be initialised when it is declared – e.g.

Structures
Example 1: Declaration

Structures and Pointers
Declaration

| Declaration of pointers to structures:
| This defines John as a structure and pJohn as a pointer to a structure.
| pJohn variable initialisation:
| pJohn can be made to point to John:
| pJohn = &John;
| new can be used to allocation memory for pJohn:
| int *pJohn = new student;

Structures and Pointers
Access to data

| The first attempt to access the fields of the structure John through pJohn can be:
| (*pJohn).StudentID;
| An alternative way:
| pJohn->StudentID;

Structures and Pointers
Example 2: Access to data

| #include <iostream.h>
| struct example { int field1; int field2; };
| int main()
| { example Structure;
| example *PointerToStructure;
| Structure.field1=12;
| PointerToStructure =& Structure; //& is necessary when dealing with structures and using pointers to them
| cout<< PointerToStructure->field1; //The -> acts somewhat like the * when used with pointers. It says, get whatever is at that memory address Not "get what that memory address is"
| return 0;
| }

Structures and pointers
Example 3: Using two structures

Structures and pointers
Example 3: Using two structures

Structures and pointers
Example 3: Using two structures

Structures
Stack principle

| NOTE: Each of the big blocks is a struct (or class) that has a pointer to another one. Remember that the pointer only stores the memory location of something, it is not that thing, so the arrow goes to the next one. At the end, there is nothing for the pointer to point to, so it does not point to anything, it should be set to "NULL" to prevent it from accidentally pointing to a totally arbitrary and random location in memory (which is very bad).

Structures
Example 3: Stack

| struct node {
| int value;
| node *next;
| };
| int main() {
| node *root; This will be the unchanging 1st node
| root=new node; Now root points to a node struct
| root->next=NULL; //The node root points to has its
| // next pointer set equal to NULL
| root->value=5; // By using the -> operator, you
| // can modify the node
| return 0; //a struct (root in this case) points to.
| }

Stack
Example 4

| int main() {
| //This won't change, or we would lose the list in memory
| //This will point to each node as it traverses the list
| //Sets it to actually point to something
| //Otherwise it would not work well
| //The conductor points to the first node
| // Creates a node at the end of the list
| //Points to that node
| //Prevents it from going any further
| }

Structures
Traversal function

| conductor=root;
| // Makes sure there is a place to start
| if(conductor!=NULL) {
| while(conductor->next!=NULL) {
| cout<<conductor->x;
| conductor=conductor->next;
| }
| cout<<conductor->x;
| }

Construct a list
Example (Step 1)

Construct a list
Example (Step 2)

Construct a list
Example (Step 3)

Construct a list
Example (Step 4)

Structures and Functions

| Functions may return pointers to structures, and they may have parameters that are pointers to structures.
| A function may return a structure, and structures may be passed as parameters.

Structures and Functions
Example Test yourself

| TASK: The program discussed shows 2 functions: *new() and new1 that create a new object for the structure

Structures
Pascal C/C++

| var
| student: record
| id: integer;
| name: packed array[1..10] of char;
| gpa: real
| end;
| struct
| { int id;
| char name[11];
| float gpa;
| } student;

Structures (Cont.)
Pascal C/C++

| var
| borrower: record
| case boolean of
| false: (EBorr: emploee);
| true: (SBorr: student)
| end;
| union
| { emploee EBorr;
| student SBorr;
| } borrower;

Structures (Cont.)
Pascal C/C++

| var
| borrower: record
| case IsStudent of
| false: (EBorr: emploee);
| true: (SBorr: student)
| end;
| NO DIRECT EQUIVALENT IN C. THIS CAN BE HANDLED BY CREATING A STRUCT WHICH CONTAINS THE TAG AND A UNION AS ITS FIELDS. (SEE NEXT SLIDE)

Structures (Cont.)
Pascal C/C++

| var
| borrower: record
| id: integer;
| name: packed array[1..10] of char;
| case boolean of
| false: (EBorr: emploee);
| true: (SBorr: student)
| end;
| struct
| { int id;
| char name[11];
| union
| { emploee EBorr;
| student SBorr;
| } Borr;
| } borrower;

Structures: Initialisation
Pascal C/C++

| NO STANDARD PASCAL EQUIVALENT (BUT MANY DIALECTS ALLOW THIS)
| A C variable may be initialised when it is declared – e.g.
| int i = 3;
| char c = ‘A’;
| float a[3] = {1.0, 2.0, 3.0};
| struct
| { char name[11];
| float gpa;
| } student = {“Smith”, 4.0};

Structures
Common errors

Structures
Things to remember

| Structures are stored in blocks of consecutive memory locations with padding if memory alignment is required.
| Structure assignments and passing a structure as a parameter involves copying the entire structure.
| C does not permit self-referential structure definitions:

Structures and Pointers
Things to remember

| Attempts to access the fields of the structure John through PointerJohn that is defined as
| PointerJohn = &John;.
| ‘.’ has higher precedence than *, so the expression
| would be interpreted as:
| The following expression is get out of the problem:
| As an alternative notation that is equivalent to the preceding expression is: